package com.gemini.main.counter;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * com.gemini.main.counter.CustomLockCounter
 * 需要对评论进行点赞次数和被评论次数进行统计，或者更多维度
 * 要求高并发、高性能计数，允许极端情况丢失一些统计次数，例如宕机
 * 评论很多，不能为每一个评论都一直保留其计数器，计数器需要有回收机制
 *
 * @author zhanghailin
 */
public class CustomLockCounter implements Counter {

    private volatile MapWithState mapWithState = new MapWithState();

    @Override
    public void save(Saver saver) {
        MapWithState preMapWithState = mapWithState;
        mapWithState = new MapWithState();
        //compareAndSet失败则表示该MapWithState正在被使用，等其使用完，它不会一直失败，因为mapWithState已经被替换
        while (!preMapWithState.state.compareAndSet(0, Integer.MIN_VALUE)) {
            Thread.yield();
        }
        preMapWithState.map.forEach((key, value) -> {
            //value已经废弃，故无需value.like.getAndSet(0)
            saver.save(key, value.like.get(), value.comment.get());
        });
    }

    @Override
    public void add(String key, int like, int comment) {
        MapWithState mapWithState;//add的并发，不可能将Integer.MIN_VALUE自增成正数(设置为Integer.MIN_VALUE时，该MapWithState已经被废弃了)
        while ((mapWithState = this.mapWithState).state.getAndIncrement() < 0);
        try {
            Adder adder = mapWithState.map.computeIfAbsent(key, k -> new Adder());
            adder.like.getAndAdd(like);
            adder.comment.getAndAdd(comment);
        } finally {
            mapWithState.state.getAndDecrement();
        }
    }

    static class Adder {
        private AtomicInteger like = new AtomicInteger();
        private AtomicInteger comment = new AtomicInteger();

    }

    static class MapWithState {
        private ConcurrentHashMap<String, Adder> map = new ConcurrentHashMap<>();
        private AtomicInteger state = new AtomicInteger();
    }
}
